using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Admin.NET.Application.Entity.Business;
using Admin.NET.Application.Service.Electricity;
using Admin.NET.Application.Service.Electricity.Dto;
using Furion.Schedule;
using Microsoft.Extensions.DependencyInjection;
using SqlSugar;

namespace Admin.NET.Application;

public class CustomRoomBillJob : IJob
{
	private readonly IServiceProvider _serviceProvider;

	private readonly ISchedulerFactory _schedulerFactory;

	public CustomRoomBillJob(IServiceProvider serviceProvider, ISchedulerFactory schedulerFactory)
	{
		_serviceProvider = serviceProvider;
		_schedulerFactory = schedulerFactory;
	}

	public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
	{
		using IServiceScope serviceScope = _serviceProvider.CreateScope();
		ISqlSugarClient db = serviceScope.ServiceProvider.GetService<ISqlSugarClient>();
		ISqlSugarClient db2 = serviceScope.ServiceProvider.GetService<ISqlSugarClient>();
		RoomService _roomService = serviceScope.ServiceProvider.GetService<RoomService>();
		try
		{
			await db.Ado.BeginTranAsync();
			await db2.Ado.BeginTranAsync();
			long templateId = long.Parse(context.JobDetail.GetProperty<string>("templateId"));
			long tenantId = long.Parse(context.JobDetail.GetProperty<string>("tenantId"));
			DateTime occurrenceTime = context.ExecutingTime;
			BillTemplate template = await (from w in db.Queryable<BillTemplate>()
				where w.Id == templateId && w.TenantId == (long?)tenantId
				select w).FirstAsync();
			if (template == null)
			{
				return;
			}
			DateTime needOccDate = template.ExpiryDate.AddDays(1.0).Date;
			if (needOccDate > occurrenceTime.Date)
			{
				template.Status = 2;
				await (from w in db.Updateable<BillTemplate>().SetColumns((BillTemplate it) => it.Status == template.Status)
					where w.TenantId == (long?)tenantId && w.Id == template.Id
					select w).ExecuteCommandAsync();
				return;
			}
			template.Status = 1;
			await (from w in db.Updateable<BillTemplate>().SetColumns((BillTemplate it) => it.Status == template.Status)
				where w.TenantId == (long?)tenantId && w.Id == template.Id
				select w).ExecuteCommandAsync();
			List<CustomRoomBill> roomBills = await (from w in db.Queryable<CustomRoomBill>()
				where w.TenantId == (long?)tenantId && w.BillTemplateId == templateId && w.Status == 1
				select w).ToListAsync();
			if (roomBills.Count == 0)
			{
				return;
			}
			List<long> roomIds = roomBills.Select((CustomRoomBill s) => s.RoomId).ToList();
			if (template.CallRules == 0)
			{
				List<long> meterIds = await (from w in db.Queryable<ElectricMeter>()
					where w.TenantId == (long?)tenantId && w.RoomId != null && roomIds.Contains((long)w.RoomId)
					select w into s
					select s.Id).ToListAsync();
				if (meterIds.Count > 0)
				{
					ElectricityService meterService = serviceScope.ServiceProvider.GetService<ElectricityService>();
					foreach (long meterId in meterIds)
					{
						InputSwitch item = new InputSwitch
						{
							Id = meterId,
							GateStatus = 1
						};
						try
						{
							meterService.SwitchMeter(item, tenantId).Wait();
						}
						catch (Exception)
						{
						}
					}
				}
			}
			else if (template.CallRules == 1)
			{
				await (from it in db.Updateable<Room>().SetColumns((Room it) => it.LimitAmount == template.LimitAmount)
					where it.TenantId == (long?)tenantId && roomIds.Contains(it.Id)
					select it).ExecuteCommandAsync();
			}
			else if (template.CallRules == 2)
			{
				foreach (CustomRoomBill item in roomBills)
				{
					decimal total = item.Bills.Select((CustomBill s) => s.Fee).Sum();
					(from w in db.Updateable<Room>().SetColumns((Room it) => it.Balance == it.Balance - total)
						where w.TenantId == (long?)tenantId && w.Id == item.RoomId
						select w).ExecuteCommand();
					item.Status = 2;
					if (total != 0m)
					{
						_roomService.AddRoomBalanceRecord(db2, item.RoomId, item.Id, 2, -total, item.TenantId.Value, "自定义账单扣除房间余额");
					}
				}
				await db.Updateable(roomBills).UpdateColumns((CustomRoomBill it) => new { it.Status }).ExecuteCommandAsync();
			}
			await db.Ado.CommitTranAsync();
			await db2.Ado.CommitTranAsync();
			_schedulerFactory.RemoveJob(context.JobId);
		}
		catch (Exception ex)
		{
			await db.Ado.RollbackTranAsync();
			await db2.Ado.RollbackTranAsync();
			throw ex;
		}
	}
}
